package com.hiof.data;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.google.gson.Gson;
import com.hiof.Configuration;
import com.hiof.beans.UserInfo;
import com.hiof.data.orm.*;
import com.hiof.servercommunication.background.job.listener.IAthletesLatestLocationReceiveListener;
import com.hiof.servercommunication.background.job.listener.INextTargetLocationListener;
import com.hiof.servercommunication.receive.beans.*;
import com.hiof.settings.user.TypeOfAttendant;
import com.hiof.settings.user.UserConfiguration;
import com.hiof.utility.Utility;
import de.greenrobot.dao.QueryBuilder;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: manish
 * Date: 4/6/12
 * Time: 8:49 PM
 * To change this template use File | Settings | File Templates.
 */
public class MoraService implements INextTargetLocationListener, IAthletesLatestLocationReceiveListener {
    private static MoraService instance;
    private SQLiteDatabase db;
    private DaoMaster daoMaster;
    private DaoSession daoSession;


    private MoraService() {
        DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(Configuration.getInstance().getApplicationContext(), "mora-db", null);
        db = helper.getWritableDatabase();
        daoMaster = new DaoMaster(db);
        daoSession = daoMaster.newSession();
    }

    public static MoraService getInstance() {
        if (null == instance) {
            instance = new MoraService();
        }
        return instance;
    }

    /**
     * This method should be called every time the activity is created inside onCreate Method
     *
     * @param context
     */
    public void refreshContext(Context context) {
    }

    public void close() {
        db.close();
    }

    public void destroy() {
        close();
        if (instance != null)
            instance = null;
        if (db != null) {
            db = null;
        }
        if (daoMaster != null) {
            daoMaster = null;
        }
        if (daoSession != null) {
            daoSession = null;
        }
    }


    private void insertSelfLocationInfo(int userID, double latitude, double longitude,
                                        double altitude, double speed, TypeOfAttendant typeOfAttendant) {
        try {
            boolean isAthlete = (typeOfAttendant == TypeOfAttendant.ATHLETE) ? true : false;
            tbl_latest_own_info info = new tbl_latest_own_info(userID, latitude, longitude, altitude, speed, isAthlete);
            daoSession.getTbl_latest_own_infoDao().insert(info);
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "insertSelfLocationInfo: " + e.getMessage());
        }
    }

    private void insertTeammateLocationInfo(int userID, double latitude, double longitude,
                                            double altitude, double speed, TypeOfAttendant typeOfAttendant) {
        try {
            boolean isAthlete = (typeOfAttendant == TypeOfAttendant.ATHLETE) ? true : false;
            tbl_latest_teammate_info teammateInfo = new tbl_latest_teammate_info(userID, latitude, longitude, altitude, speed, isAthlete);
            daoSession.getTbl_latest_teammate_infoDao().insert(teammateInfo);
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "insertTeammateLocationInfo: " + e.getMessage());
        }
    }

    private void insertNextTargetLocation(String targetName, double latitude, double longitude, double altitude, double distance, double predictedTime) {
        try {
            tbl_next_target entity = new tbl_next_target(distance, latitude, longitude, altitude, predictedTime, targetName);
            daoSession.getTbl_next_targetDao().insert(entity);
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "insertNextTargetLocation(): " + e.getMessage());
        }
    }

    private void saveNextTargetLocation(double distance, double latitude, double longitude, double altitude, double predictedTime, String targetName) {
        try {
            daoSession.getTbl_next_targetDao().deleteAll();
            insertNextTargetLocation(targetName, latitude, longitude, altitude, distance, predictedTime);
        } catch (Exception e) {
            if (e != null)
                Utility.error(this.getClass().toString(), "saveNextTargetLocation(): " + e.getMessage());
        }
    }

    public void saveSelfLocationInfo(int userId, double latitude, double longitude, double altitude, double speed, TypeOfAttendant typeOfAttendant) {
        try {
            daoSession.getTbl_latest_own_infoDao().deleteAll();
            insertSelfLocationInfo(userId, latitude, longitude, altitude, speed, typeOfAttendant);
        } catch (Exception e) {
            if (e != null)
                Utility.error(this.getClass().toString(), "saveSelfLocationInfo(): " + e.getMessage());
        }
    }

    private void saveAthleteLocationInfoWhenUserIsSupport(AthleteLocationReceivePacket athleteLocationReceivePacket) {
        daoSession.getTbl_latest_teammate_infoDao().deleteAll();
        UserInfo athleteInfo = UserConfiguration.getInstance().getAthleteWhenUserIsSupport();
        if (athleteInfo != null) {
            insertTeammateLocationInfo(athleteInfo.getUserId(),
                    athleteLocationReceivePacket.getLat(),
                    athleteLocationReceivePacket.getLng(),
                    athleteLocationReceivePacket.getHeight(),
                    athleteLocationReceivePacket.getSpeed(), athleteInfo.getTypeOfAttendant());
        }
    }

    private void saveSupportLocationInfoWhenUserIsAthlete(List<MemberLocationInfo> memberList) {
        daoSession.getTbl_latest_teammate_infoDao().deleteAll();
        for (MemberLocationInfo memberLocationInfo : memberList) {
            GeoPoint geoPoint = memberLocationInfo.getGeoPoint();
            UserInfo memberInfo = UserConfiguration.getInstance().getTeammateByUserId(memberLocationInfo.getUserid());
            insertTeammateLocationInfo(memberLocationInfo.getUserid(), geoPoint.getLat(), geoPoint.getLng(), geoPoint.getAltitude(), memberLocationInfo.getSpeed(), memberInfo.getTypeOfAttendant());
        }
    }

    public GeoPoint getSelfLocationInfo() {
        try {
            List<tbl_latest_own_info> entities = daoSession.getTbl_latest_own_infoDao().loadAll();
            if (entities != null && entities.size() > 0) {
                tbl_latest_own_info entity = entities.get(0);
                if (entity != null && entity.getUserId() == UserConfiguration.getInstance().getUserId()) {
                    return new GeoPoint(entity.getLatitude(), entity.getLongitude(), entity.getAltitude());
                } else {
                    return new GeoPoint();
                }
            } else {
                return new GeoPoint();
            }
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "getSelfLocationInfo()" + e.getMessage());
            return new GeoPoint();
        }
    }

    public double getSelfSpeed() {
        try {
            List<tbl_latest_own_info> entities = daoSession.getTbl_latest_own_infoDao().loadAll();
            if (entities != null && entities.size() > 0) {
                tbl_latest_own_info entity = entities.get(0);
                if (entity != null && entity.getUserId() == UserConfiguration.getInstance().getUserId()) {
                    return entity.getSpeed();
                } else {
                    return -1;
                }
            } else {
                return -1;
            }
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "getSelfSpeed()" + e.getMessage());
            return -1;
        }
    }

    public void saveUserConfigurationInstance(UserConfiguration instance) {
        String configName = UserConfiguration.class.toString();
        Gson gson = new Gson();
        String jsonValue = gson.toJson(instance);
        Utility.debug(this.getClass().toString(), "saving user configuration:" + jsonValue);
        saveConfigurationData(configName, jsonValue);
    }

    public UserConfiguration getUserConfigurationInstance() {
        String configName = UserConfiguration.class.toString();
        String jsonValue = getConfigurationData(configName);

        Utility.debug(this.getClass().toString(), "jsonVal:" + jsonValue);
        if (jsonValue == null || jsonValue.equals("") || jsonValue.contains("\"userId\":0")) {
            return null;
        }
        Gson gson = new Gson();
        return gson.fromJson(jsonValue, UserConfiguration.class);
    }

    public void deleteConfigurationInstance() {
        String configName = UserConfiguration.class.toString();
        deleteConfigurationData(configName);
    }

    private void saveConfigurationData(String configName, String jsonValue) {
        try {
            deleteConfigurationData(configName);

            daoSession.getTbl_configDao().insert(new tbl_config(configName, jsonValue));
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "saveConfigurationData()" + e.getMessage());
        }
    }

    private void deleteConfigurationData(String configName) {
        daoSession.getTbl_configDao().queryBuilder().
                where(tbl_configDao.Properties.Config_name.eq(configName))
                .buildDelete();
    }

    private String getConfigurationData(String configName) {
        try {

            List<tbl_config> entities = daoSession.getTbl_configDao().queryBuilder()
                    .where(tbl_configDao.Properties.Config_name.eq(configName))
                    .list();
            if (entities != null) {
                tbl_config entity = entities.get(0);
                Utility.debug(this.getClass().toString(), "Entity:" + entity.getJson_value());
                if (entity != null) {
                    return entity.getJson_value();
                }
            }
            return "";
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "getConfigurationData()" + e.getMessage());
            return "";
        }
    }

    public TargetInfoPacket getNextTargetInfo() {
        TargetInfoPacket nextTargetInfo = new TargetInfoPacket();
        try {
            List<tbl_next_target> entities = daoSession.getTbl_next_targetDao().loadAll();
            if (entities != null) {
                tbl_next_target entity = entities.get(0);
                nextTargetInfo.setDistance(entity.getDistance());
                nextTargetInfo.setGeoPoint(new GeoPoint(entity.getLatitude(), entity.getLongitude(), entity.getAltitude()));
                nextTargetInfo.setPredictedTime(entity.getPredicted_time());
                nextTargetInfo.setTargetName(entity.getTargetName());
            }
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "getNextTargetInfo: " + e.getMessage());
        }
        return nextTargetInfo;
    }

    public void saveHeartRateValue(int athleteID, int heartRate, String status) {
        try {
            daoSession.getTbl_heart_rateDao().insert(new tbl_heart_rate(athleteID, new Date(), heartRate, status));
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "saveHeartRateValue: " + e.getMessage());
        }
    }

    public List<tbl_heart_rate> getHeartRatesByAthleteId(int athleteId) {
        List<tbl_heart_rate> heartRates = new ArrayList<tbl_heart_rate>();
        try {
            QueryBuilder queryBuilder = daoSession.getTbl_heart_rateDao().queryBuilder();
            queryBuilder.where(tbl_heart_rateDao.Properties.AthleteId.eq(athleteId));
            if (queryBuilder.list().size() > 0)
                heartRates = queryBuilder.list();
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "getNextTargetInfo: " + e.getMessage());
        }
        return heartRates;
    }

    public int getLatestHeartRate() {
        int heartRate = 0;
        try {
            QueryBuilder queryBuilder = daoSession.getTbl_heart_rateDao().queryBuilder();
            queryBuilder.orderDesc(tbl_heart_rateDao.Properties.Time);
            if (!queryBuilder.list().isEmpty())
                heartRate = ((tbl_heart_rate) queryBuilder.list().get(0)).getHeart_rate_bpm();
        } catch (Exception e) {
            Utility.error(this.getClass().toString(), "getLatestHeartRate: " + e.getMessage());
        }
        return heartRate;
    }

    @Override
    public void onListen(Packet packet) {
        if (packet instanceof TargetInfoPacket) {
            TargetInfoPacket targetInfoPacket = (TargetInfoPacket) packet;
            Utility.debug(this.getClass().toString(), "Target Information Received");
            double distance = targetInfoPacket.getDistance();
            double latitude = targetInfoPacket.getGeoPoint().getLat();
            double longitude = targetInfoPacket.getGeoPoint().getLng();
            double predictedTime = targetInfoPacket.getPredictedTime();
            double altitude = targetInfoPacket.getGeoPoint().getAltitude();
            String targetName = targetInfoPacket.getTargetName();

            saveNextTargetLocation(distance, latitude, longitude, altitude, predictedTime, targetName);
        } else if (packet instanceof TeamMemberLocationPacket) {
            Utility.debug(this.getClass().toString(), "Team members location Received");
            TeamMemberLocationPacket teamMemberLocationPacket = (TeamMemberLocationPacket) packet;

            List<MemberLocationInfo> memberList = teamMemberLocationPacket.getTeamMemberLocations();

            saveSupportLocationInfoWhenUserIsAthlete(memberList);
            Utility.debug(this.getClass().toString(), "packet receive");
        } else if (packet instanceof AthleteLocationReceivePacket) {
            Utility.debug(this.getClass().toString(), "Athlete Location Received");

            AthleteLocationReceivePacket athleteLocationReceivePacket = (AthleteLocationReceivePacket) packet;
            saveAthleteLocationInfoWhenUserIsSupport(athleteLocationReceivePacket);
        }
    }
}
